package sample.plugin;

import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;

import org.apache.commons.beanutils.PropertyUtils;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang.ArrayUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang.builder.ToStringBuilder;
import org.netbeans.nbbuild.VerifyClassLinkageForTest02;

import sample.plugin.model.CaseIntroDto;
import tw.gov.moi.ae.selenium.common.annotations.CaseIntro;

public class ExtractByByte {
	private static final String ATART_Tag ="L.*;";
	private static final String TAG = getTagName();
	
	public static void main(String[] args) throws IOException {
		VerifyClassLinkageForTest02 v2 = new VerifyClassLinkageForTest02();
		InputStream is = new FileInputStream("/media/SSD/IISI/workspaces/myeclipse2014/SRIS OP TEST CASE/target/test-classes/tw/gov/moi/op/OpLoginTest001.class") ;
		byte[] data = IOUtils.toByteArray(is );
		List<String> src = v2.readByteCode(data);
		
		final List<CaseIntroDto>  result = new ExtractByByte().convert(src);
		for (CaseIntroDto unit : result) {
			System.out.println(ToStringBuilder.reflectionToString(unit));
			
		}		
	}
	private static  String getTagName(){
		return String.format("L%s;", 	CaseIntro.class.getCanonicalName().replace(".","/"));	
	}
	public  List<CaseIntroDto>  convert(List<String>  sampleList ){
		final List<CaseIntroDto> finalData  =new ArrayList<CaseIntroDto>();
		final List<Interval> initialData = new MatcherCondition().extractIntervals(sampleList);
		final List<Interval> finalResult = new ArrayList<ExtractByByte.Interval>();
		for(final Interval interval : initialData){
			if(TAG.equalsIgnoreCase(interval.getName())){
				finalResult.add(interval);
			}
		}
		if(finalResult.size() > 0){
			for(final Interval interval : finalResult){
				
				final CaseIntroDto unitDto = new CaseIntroDto();
				
				final List<Interval> attributes = new CollectionCondition().extractIntervals(interval.getContent());
				for(Interval attr : attributes){
					final String propertyName = attr.getName() ; 
					attr.getContent().remove(propertyName);
					final 	String value = StringUtils.join(attr.getContent() ,"\r");
					 
					
					try {
						PropertyUtils.setProperty(unitDto, propertyName, value);
					} catch (IllegalAccessException e) {
						e.printStackTrace();
					} catch (InvocationTargetException e) {
						e.printStackTrace();
					} catch (NoSuchMethodException e) {
						e.printStackTrace();
					}
					
				}
				
				finalData.add(unitDto);
			}
		}
		return finalData;
	}	
	
	class Interval {
		private Integer startLineNo;
		private Integer endLineNo;
		private String name ;
		private List<String> content ;
		public Integer getStartLineNo() {
			return startLineNo;
		}
		public void setStartLineNo(Integer startLineNo) {
			this.startLineNo = startLineNo;
		}
		public Integer getEndLineNo() {
			return endLineNo;
		}
		public void setEndLineNo(Integer endLineNo) {
			this.endLineNo = endLineNo;
		}
		public String getName() {
			return name;
		}
		public void setName(String className) {
			name = className;
		}
		public List<String> getContent() {
			return content;
		}
		public void setContent(List<String> content) {
			this.content = content;
		}
		
	}
	abstract class AbstractConditionClass{
		abstract boolean condition(String line);
		public List<Interval> extractIntervals (final List<String>  sampleList ){
			final List<Interval> result =new ArrayList<Interval>();
			Integer reservedLine = null;
			String  reservedClassName = null;
			for(int i=0 ; i<sampleList.size() ;++i){
				final String line  = sampleList.get(i);
				boolean needProcess =false ; 
				
				if(condition(line)){
					needProcess = true ;					
				}else if( (i == sampleList.size()-1) && reservedLine != null && reservedClassName !=null){
					needProcess = true ;
				}
				
				if(needProcess){
					if (reservedLine != null && reservedClassName != null) {
						final Interval interval = new Interval();
						interval.setName(reservedClassName);
						interval.setStartLineNo(reservedLine);
						if(i!=(sampleList.size()-1)){
							interval.setEndLineNo(i -1);
						}else{
							interval.setEndLineNo(i);
						}
					
						final List<String> unitList = new ArrayList<String>();
						for (int j = interval.getStartLineNo(); j <= interval.getEndLineNo(); j++) {
							unitList.add(sampleList.get(j));
						}
						
						interval.setContent(unitList);
						result.add(interval);
					}

					reservedLine = i;
					reservedClassName = line;
				}
			} 
			return result;
		}
	}
	class MatcherCondition extends AbstractConditionClass{ 
		boolean condition(String line) {
			return line.matches(ATART_Tag);
		}
	}
	class CollectionCondition extends AbstractConditionClass{		
		boolean condition(String line) {			
			final Method[] fields = CaseIntro.class.getDeclaredMethods();
			String[] scopeList = new String[fields.length];
			
			for(int i =0 ; i< fields.length ;++i){
				scopeList[i] = fields[i].getName();
			}
			boolean result = ArrayUtils.contains(scopeList, line);
			return result;
		}
	}
}
